package com.dd.admin.service.impl;

import cn.dev33.satoken.stp.SaTokenInfo;
import cn.dev33.satoken.stp.StpUtil;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.core.conditions.update.LambdaUpdateWrapper;
import com.dd.common.convert.SysUserConvert;
import com.dd.common.dto.system.user.SysUserLoginDTO;
import com.dd.common.vo.SysUserLoginVO;
import com.dd.admin.service.AuthService;
import com.dd.common.config.GlobalConfig;
import com.dd.common.entity.SysLoginLog;
import com.dd.common.entity.SysUser;
import com.dd.common.enums.ErrorEnum;
import com.dd.common.exception.BusinessException;
import com.dd.common.mapper.SysLoginLogMapper;
import com.dd.common.mapper.SysUserMapper;
import com.dd.common.utils.IpUtils;
import com.dd.common.utils.RequestContextUtils;
import com.dd.common.utils.StrGenerator;
import eu.bitwalker.useragentutils.UserAgent;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.scheduling.annotation.Async;
import org.springframework.stereotype.Service;

import java.time.LocalDateTime;
import java.util.Objects;

@Service
public class AuthServiceImpl implements AuthService {

    @Autowired
    private SysUserMapper sysUserMapper;
    @Autowired
    private SysUserConvert sysUserConvert;
    @Autowired
    private SysLoginLogMapper sysLoginLogMapper;

    @Override
    public SysUserLoginVO login(SysUserLoginDTO dto) {
        String rawPassword = dto.getPassword();
        String username = dto.getUsername();
        String email = dto.getEmail();
        String phone = dto.getPhone();

        String ip = IpUtils.getIp();

        // 1. 按优先级查找用户
        SysUser user = null;

        // 按优先级查找用户
        if (username != null && !username.trim().isEmpty()) {
            user = sysUserMapper.selectOne(new LambdaQueryWrapper<SysUser>().eq(SysUser::getUsername, username));
        }

        if (user == null && email != null && !email.trim().isEmpty()) {
            user = sysUserMapper.selectOne(new LambdaQueryWrapper<SysUser>().eq(SysUser::getEmail, email));
        }

        if (user == null && phone != null && !phone.trim().isEmpty()) {
            user = sysUserMapper.selectOne(new LambdaQueryWrapper<SysUser>().eq(SysUser::getPhone, phone));
        }

        if (user == null) {
            createLoginLog(username, ip, GlobalConfig.STATUS_DISABLE, ErrorEnum.USER_NOT_FOUND.getMsg());
            throw new BusinessException(ErrorEnum.USER_NOT_FOUND);
        }

        if (!Objects.equals(user.getStatus(), GlobalConfig.STATUS_ENABLE)) {
            createLoginLog(user.getUsername(), ip, GlobalConfig.STATUS_DISABLE, ErrorEnum.USER_DISABLED.getMsg());
            throw new BusinessException(ErrorEnum.USER_DISABLED);
        }

//        if (!passwordEncoder.matches(rawPassword, user.getPassword())) {
//            throw new BusinessException(ErrorEnum.PASSWORD_ERROR);
//        }
        if (!user.getPassword().equals(StrGenerator.makeMd5(rawPassword))) {
            createLoginLog(user.getUsername(), ip, GlobalConfig.STATUS_DISABLE, ErrorEnum.PASSWORD_ERROR.getMsg());
            throw new BusinessException(ErrorEnum.PASSWORD_ERROR);
        }

        // sa-token 登录
        StpUtil.login(user.getId());
        // sa-token 有三种 Session 模型：account-session token-session custom-session
        // account-session: 对应账号范围，比如：PC、手机多设备同账号登录，它们共享同一个 account-session
        // token-session: 对应Token范围，比如同样是多设备登录，但每个设备的token肯定都不一样，所以每个设备都有各自隔离的 token-session
        // Custom-Session不依赖特定的 账号id 或者 token，而是依赖于你提供的SessionId
        StpUtil.getSession().set(GlobalConfig.CURRENT_USER, user);
        SaTokenInfo tokenInfo = StpUtil.getTokenInfo();

        // 记录登录IP和时间
        updateLoginInfo(user.getId(), ip);
        // 创建登录日志
        createLoginLog(user.getUsername(), ip, GlobalConfig.STATUS_ENABLE, "登录成功");

        SysUserLoginVO vo = sysUserConvert.entityToLoginVO(user);
        vo.setToken(tokenInfo.getTokenValue());
        return vo;
    }

    /**
     * 更新登录信息
     */
    @Async  // 异步执行
    public void updateLoginInfo(Long userId, String ip) {
        sysUserMapper.update(null,
                new LambdaUpdateWrapper<SysUser>()
                        .eq(SysUser::getId, userId)
                        .set(SysUser::getLastLoginTime, LocalDateTime.now())
                        .set(SysUser::getLastLoginIp, ip)
        );

    }

    /**
     * 记录登录日志
     */
    @Async
    public void createLoginLog(String username, String ip, Integer status, String msg) {
        UserAgent userAgent = RequestContextUtils.getUserAgent();
        SysLoginLog loginLog = new SysLoginLog();
        loginLog.setUsername(username);
        loginLog.setIp(ip);
        loginLog.setLocation(IpUtils.getIp2region(ip));
        loginLog.setStatus(status);
        loginLog.setMsg(msg);
        if (userAgent != null) {
            loginLog.setBrowser(userAgent.getBrowser().getName());
            loginLog.setOs(userAgent.getOperatingSystem().getName());
        }
        sysLoginLogMapper.insert(loginLog);
    }
}
